package com.lqk.demo.pessimisticlock.syncmode.guardedsuspension;


import com.lqk.demo.n2.util.Sleeper;
import lombok.extern.slf4j.Slf4j;

import java.util.Hashtable;
import java.util.Map;
import java.util.Set;

@Slf4j(topic = "c.Test20")
public class Test20 {
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            new People().start();
        }
        Sleeper.sleep(1);
        // 获取需要送的所有信
        for (Integer id : MailBoxes.getIds()) {
            new Postman(id,"内容"+id).start();
        }
    }
}

@Slf4j(topic = "c.People")
class People extends Thread {
    @Override
    public void run() {
        // 收信
        GuardedObject1 guardedObject = MailBoxes.createGuardedObject();
        log.debug("开始收信id：{}",guardedObject.getId());
        Object mail = guardedObject.get(5000);
        log.debug("收到信id：{}，内容：{}",guardedObject.getId(),mail);
    }
}

@Slf4j(topic = "c.Postman")
class Postman extends Thread {

    private int mailBoxId;

    private String mail;

    public Postman(int mailBoxId, String mail) {
        this.mailBoxId = mailBoxId;
        this.mail = mail;
    }

    @Override
    public void run() {
        GuardedObject1 guardedObject = MailBoxes.getGuardedObjectById(mailBoxId);
        log.debug("送信id：{}，内容：{}",mailBoxId,mail);
        guardedObject.complete(mail);
    }
}

class MailBoxes {
    private static Map<Integer, GuardedObject1> boxes = new Hashtable<>();

    // 实际生产中是UUID
    private static int id = 1;

    // 产生唯一ID
    private static synchronized int generateId() {
        // 实际生产中是UUID，而不是自增ID，这里只是方便看到程序运行的逻辑
        return id++;
    }

    public static GuardedObject1 getGuardedObjectById(int id){
        // 表示将GuardedObject从Map中返回该对象后删除
        return boxes.remove(id);
    }

    // 产生
    public static GuardedObject1 createGuardedObject() {
        GuardedObject1 go = new GuardedObject1(generateId());
        boxes.put(go.getId(), go);
        return go;
    }

    public static Set<Integer> getIds() {
        return boxes.keySet();
    }

}

class GuardedObject1 {

    // 标识 GuardedObject
    private int id;
    // 结果
    private Object response;

    public GuardedObject1(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    // 获取结果的方法
    // timeout 表示要等待多久
    public Object get(long timeout) {
        synchronized (this) {
            // 记录开始等待时间
            long begin = System.currentTimeMillis();
            // 经历的时间
            long passTime = 0;
            // 表示没有结果
            while (response == null) {
                // 这一轮循环应该等待的时间
                long waitTime = timeout - passTime;
                // 经历的时间超过了最大的等待时间，退出循环
                if (waitTime <= 0) {
                    break;
                }
                try {
                    /**
                     * 不直接使用timeout是避免虚假唤醒后重新等待timeout的时间
                     */
                    this.wait(waitTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 求得经历时间
                passTime = System.currentTimeMillis() - begin;
            }
            return response;
        }
    }

    // 产生结果的方法
    public void complete(Object response) {
        synchronized (this) {
            // 将结果赋值给成员变量
            this.response = response;
            this.notifyAll();
        }
    }

}

